package memoryPatch;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Logger;

import javax.servlet.http.*;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;




@SuppressWarnings("serial")
public class TaskHandler extends HttpServlet {

	private static final Logger log = Logger.getLogger(TaskHandler.class.getName());
	private static final DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {

		log.warning("Received GET in TaskHandler");
		log.info(req.toString());
		log.info(req.getRequestURL().toString());	
		
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		String userString = "";
		if (user != null) {
			userString = user.toString();
			log.info("User:" + userString);
		}
		else {
			log.info("User: (null)");
		}
		//need to do authentication to make this work correctly
		
		Query query = new Query("Task");
		query.addFilter("user", Query.FilterOperator.EQUAL, userString);
		PreparedQuery preparedQuery = datastore.prepare(query);
		Task tempTask = null;
		String output = "";
		PrintWriter writer = resp.getWriter();
		JSONObject tempJsonObject = null;
		JSONStringer stringer = new JSONStringer();
		try {
			stringer.array();
		} catch (JSONException e1) {
			log.warning("Stringer could not begin array");
		}
		for (Entity result : preparedQuery.asIterable())
		{
			log.info("Query returned a result:" + result.toString());
			tempTask = new Task(result);
			tempJsonObject = tempTask.getJSONObject();
			try {
				stringer.value( tempJsonObject );
			} catch (JSONException e) {
				log.warning("Couldn't add JSON object to stringer");
			}
			tempJsonObject = null;
		}
		try {
			stringer.endArray();
		} catch (JSONException e) {
			log.warning("Stringer could not end array");
		}
		output = stringer.toString();
		log.info("Output written to client:" + output);
		writer.write(output);
		/*
		JSONObject test = new JSONObject();
		try {
		test.put("done", true);
		test.put("content", "Task from the server!");
		test.put("order", 777);
		} catch (JSONException e) {
			log.warning("Exception in creating JSON Object to send");
		}
		resp.getWriter().write(test.toString());
		*/

	}
	
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		// this method currently is used to post new objects as well as changes to current objects
		// this method SHOULD only be used for posting new objects
		
		log.info("Received POST in TaskHandler");
		//log.info(req.toString());

		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		String userString = "";
		if (user != null) {
			userString = user.toString();
			log.info("User:" + userString);
		}
		else {
			log.info("User: (null)");
		}
		
		if(req.getRequestURL() != null) {
			log.info(req.getRequestURL().toString());
		}
		
		//got the basis of how to parse JSON from a POST from:
		//http://stackoverflow.com/questions/3831680/httpservletrequest-get-post-data
		StringBuffer jb = new StringBuffer();
		String line = null;
		
		try {
		    BufferedReader reader = req.getReader();
		    while ((line = reader.readLine()) != null)
		      jb.append(line);
		} catch (Exception e) { 
			log.warning("Error in reading request content");
		}
		log.info(jb.toString());
		Task task = new Task(jb.toString(), userString);
		Entity curEnt = task.makeEntity();
		//log.info("Entity content: " + curEnt.getProperty("content"));
		//log.info("Entity done: " + curEnt.getProperty("done").toString());
		//log.info("Entity order: " + curEnt.getProperty("order").toString());
		//log.info("Entity user: " + curEnt.getProperty("user").toString());
		
		
		//as of right now, the order property is non-unique, so this doesn't really work
		
		//what we should do is make a taskId with the following properties:
		// -blank for new tasks, then generate one from the datastore key and then send it back to the client
		// -sent in the request for updates to existing tasks so we're not duplicating tasks in the datastore
		//if this functionality stays in the POST handler, the client MUST track the taskId so we can check to see if the task already exists
		datastore.put(curEnt);
		//update datastore, update client
		resp.getWriter().write(task.getJSONString());

	}


	public void doPut(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		// This method appears to never be used
		// This method should be used to update objects
		log.info("Received PUT in TaskHandler");
		log.info(req.toString());
		
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		String userString = "";
		if (user != null) {
			userString = user.toString();
			log.info("User:" + userString);
		}
		else {
			log.info("User: (null)");
		}
		
		if(req.getRequestURL() != null) {
			log.info(req.getRequestURL().toString());
		}
		
		//got the basis of how to parse JSON from a POST from:
		//http://stackoverflow.com/questions/3831680/httpservletrequest-get-post-data
		StringBuffer jb = new StringBuffer();
		String line = null;
		
		try {
		    BufferedReader reader = req.getReader();
		    while ((line = reader.readLine()) != null)
		      jb.append(line);
		} catch (Exception e) { 
			log.warning("Error in reading request content");
		}
		log.info(jb.toString());
		Task task = new Task(jb.toString(), userString);
		
		// now that we have the task, we should reference the taskId and edit the appropriate entity
		long taskId = task.getTaskId();
		Query query = new Query("Task");
		query.addFilter("taskId", Query.FilterOperator.EQUAL, taskId);
		query.addFilter("user", Query.FilterOperator.EQUAL, userString);
		PreparedQuery preparedQuery = datastore.prepare(query);
		Entity result = preparedQuery.asSingleEntity();
		if (result == null) {
			log.warning("Queried for taskId " + taskId + " returned no results");
		}
		else {
			task.setEntity(result);
			datastore.put(result);
			resp.getWriter().write(task.getJSONString());
		}

	}
	
	public void doDelete(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		// This method appears to never be used yet
		// This handler should be used to delete a given task
		log.info("Received DELETE in TaskHandler");
		log.info(req.toString());
		
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		String userString = "";
		if (user != null) {
			userString = user.toString();
			log.info("User:" + userString);
		}
		else {
			log.info("User: (null)");
		}
		
		if(req.getRequestURL() != null) {
			log.info(req.getRequestURL().toString());
		}
		
		//got the basis of how to parse JSON from a POST from:
		//http://stackoverflow.com/questions/3831680/httpservletrequest-get-post-data
		StringBuffer jb = new StringBuffer();
		String line = null;
		
		try {
		    BufferedReader reader = req.getReader();
		    while ((line = reader.readLine()) != null)
		      jb.append(line);
		} catch (Exception e) { 
			log.warning("Error in reading request content");
		}
		log.info(jb.toString());
		Task task = new Task(jb.toString(), userString);
		
		// now that we have the task, we should reference the taskId and edit the appropriate entity
		long taskId = task.getTaskId();
		Query query = new Query("Task");
		query.addFilter("taskId", Query.FilterOperator.EQUAL, taskId);
		query.addFilter("user", Query.FilterOperator.EQUAL, userString);
		PreparedQuery preparedQuery = datastore.prepare(query);
		Entity result = preparedQuery.asSingleEntity();
		if (result == null) {
			log.warning("Queried for taskId " + taskId + " returned no results");
		}
		else {
			datastore.delete(result.getKey());
			// probably a better solution is to use a bool property "deleted"
			// then filter the view on the deleted property
			// that way metrics can be gathered and users can view their completed tasks
		}

	}


}